package org.obm.mina;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

public class LineBuffer {
	private ByteBuffer buf;
	private boolean complete;

	public LineBuffer() {
	}

	public LineBuffer(int size) {
		buf = ByteBuffer.allocate(size);
	}

	/**
	 * Parses text line bytes from remaining bytes in the specified ByteBuffer
	 * until a terminating LF is reached, in which case the ByteBuffer position
	 * will be advanced to the character which immediately followed the LF.
	 * Otherwise, if no LF was encountered than all remaining characters in 'bb'
	 * are consumed.
	 * 
	 * @param bb
	 *            the ByteBuffer from which bytes are to be parsed
	 * @return true if line is complete, false otherwise
	 */
	public boolean parse(ByteBuffer bb) {
		if (!complete) {
			int pos = indexOf(bb, '\n');
			if (pos >= 0) {
				int len = pos + 1 - bb.position();
				ByteBuffer tmp = bb.slice();
				tmp.limit(len);
				bb.position(pos + 1);
				buf = MinaUtil.expand(buf, len, len).put(tmp);
				buf.flip();
				complete = true;
			} else {
				buf = MinaUtil.expand(buf, bb.remaining()).put(bb);

			}
		}
		return complete;
	}

	public boolean matches(String s) {
		return s.length() == size() && startsWith(s);
	}

	public boolean startsWith(String s) {
		if (s.length() <= size()) {
			for (int i = 0; i < s.length(); i++) {
				if (s.charAt(i) != buf.get(i)) {
					return false;
				}
			}
			return true;
		}
		return false;
	}

	public ByteBuffer buf() {
		return buf;
	}

	public int size() {
		return complete ? buf.limit() : buf.position();
	}

	public String toString() {
		return toString(size());
	}

	public String toString(int len) {
		try {
			return new String(buf.array(), buf.arrayOffset(), len, "ASCII");
		} catch (UnsupportedEncodingException e) {
			throw new InternalError("ASCII charset missing");
		}
	}

	public void reset() {
		buf.clear();
		complete = false;
	}

	private static int indexOf(ByteBuffer bb, char c) {
		int limit = bb.limit();
		for (int pos = bb.position(); pos < limit; pos++) {
			if (bb.get(pos) == c)
				return pos;
		}
		return -1;
	}
}
